import tkinter as tk
from tkinter import ttk, filedialog
from tkinter import messagebox
import os
from openpyxl import load_workbook, Workbook
import traceback
from tkcalendar import DateEntry
from PIL import Image, ImageTk
import logging

# 配置日志记录
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')

# 列名
columns = ("序号", "需求来源", "定制时间", "客户信息", "项目编号", "需求简单描述", "当前华为基线版本",
           "发布最新版本", "对应华为主板型号", "华鲲机型", "工作量评估",
           "git 分支和路径", "备注")

# 需求来源的可选值
source_options = ["自研项目", "市场一线项目", "华为合作项目", "POC 团队", "其他"]

# 增大字体
FONT_SIZE = 12
# 普通字体
FONT = ("微软雅黑", FONT_SIZE)
# 加粗字体
FONT_BOLD = ("微软雅黑", FONT_SIZE, "bold")
# 版权声明字体（调小）
DISCLAIMER_FONT = ("微软雅黑", FONT_SIZE - 2)

# 标题字体
TITLE_FONT = ("微软雅黑", 24, "bold")

# 从 Excel 文件读取项目数据
def read_projects_from_excel(file_path):
    try:
        wb = load_workbook(file_path)
        ws = wb.active
        projects = []
        for row in ws.iter_rows(min_row=2, values_only=True):
            project = dict(zip(columns[1:], row[1:]))
            projects.append(project)
        return projects
    except Exception as e:
        print(f"读取 Excel 文件时出现异常：{str(e)}")
        traceback.print_exc()
        return []

# 将项目数据保存到 Excel 文件
def save_projects_to_excel(file_path, projects):
    try:
        wb = Workbook()
        ws = wb.active
        # 写入表头
        ws.append(columns)
        # 写入项目数据
        for i, project in enumerate(projects):
            row = [i + 1] + [project.get(col, "") for col in columns[1:]]
            ws.append(row)
        wb.save(file_path)
    except Exception as e:
        print(f"保存 Excel 文件时出现异常：{str(e)}")
        traceback.print_exc()

# 检查文件是否存在，不存在则创建
def check_and_create_excel(file_path):
    if not os.path.exists(file_path):
        try:
            wb = Workbook()
            ws = wb.active
            ws.append(columns)
            wb.save(file_path)
            messagebox.showinfo("提示", f"已成功创建 {file_path} 文件。")
        except Exception as e:
            print(f"创建 Excel 文件时出现异常：{str(e)}")
            traceback.print_exc()
            messagebox.showerror("错误", f"创建文件失败：{str(e)}")

# 项目信息数据，从 Excel 文件读取
file_path = "projects.xlsx"
projects = read_projects_from_excel(file_path)

def add_project():
    try:
        values = get_input_values()
        if not all(values):
            messagebox.showwarning("警告", "请填写所有项目信息！")
            return
        new_project = dict(zip(columns[1:], values))
        projects.append(new_project)
        update_project_numbers()
        show_all_projects()
        clear_inputs()
        update_project_number_options()
        save_projects_to_excel(file_path, projects)
    except Exception as e:
        print(f"新增项目时出现异常：{str(e)}")
        traceback.print_exc()
        messagebox.showerror("错误", f"新增项目失败：{str(e)}")


def delete_project():
    try:
        selected_item = tree.selection()
        if not selected_item:
            messagebox.showwarning("警告", "请选择要删除的项目！")
            return
        item = selected_item[0]
        index = int(tree.item(item, "values")[0]) - 1
        del projects[index]
        update_project_numbers()
        show_all_projects()
        update_project_number_options()
        save_projects_to_excel(file_path, projects)
    except Exception as e:
        print(f"删除项目时出现异常：{str(e)}")
        traceback.print_exc()
        messagebox.showerror("错误", f"删除项目失败：{str(e)}")


def modify_project():
    try:
        selected_item = tree.selection()
        if not selected_item:
            messagebox.showwarning("警告", "请选择要修改的项目！")
            return
        item = selected_item[0]
        index = int(tree.item(item, "values")[0]) - 1
        project = projects[index]
        values = get_input_values()
        for i, col in enumerate(columns[1:]):
            project[col] = values[i]
        if not all([project[col] for col in columns[1:]]):
            messagebox.showwarning("警告", "请填写所有项目信息！")
            return
        update_project_numbers()
        show_all_projects()
        clear_inputs()
        save_projects_to_excel(file_path, projects)
    except Exception as e:
        print(f"修改项目时出现异常：{str(e)}")
        traceback.print_exc()
        messagebox.showerror("错误", f"修改项目失败：{str(e)}")


def filter_project():
    try:
        selected_project_number = selected_project_number_var.get()
        if selected_project_number == "全部项目":
            show_all_projects()
        else:
            for item in tree.get_children():
                tree.delete(item)
            for i, project in enumerate(projects):
                if project["项目编号"] == selected_project_number:
                    insert_project_to_tree(project, i)
    except Exception as e:
        print(f"筛选项目时出现异常：{str(e)}")
        traceback.print_exc()
        messagebox.showerror("错误", f"筛选项目失败：{str(e)}")


def get_input_values():
    values = []
    for entry in entries:
        if isinstance(entry, tk.OptionMenu):
            values.append(selected_source.get())
        elif isinstance(entry, DateEntry):
            values.append(entry.get())
        elif isinstance(entry, tk.Text):
            values.append(entry.get("1.0", tk.END).strip())
        else:
            values.append(entry.get())
    return values


def insert_project_to_tree(project, index):
    try:
        # 确保项目字典包含所有必要的键
        for col in columns[1:]:
            if col not in project:
                project[col] = ""
        values = [index + 1] + [project[col] for col in columns[1:]]
        tree.insert("", "end", values=values)
    except Exception as e:
        print(f"插入项目到表格时出现异常：{str(e)}")
        traceback.print_exc()
        messagebox.showerror("错误", f"插入项目到表格失败：{str(e)}")


def clear_inputs():
    for i, entry in enumerate(entries):
        if isinstance(entry, tk.OptionMenu):
            selected_source.set(source_options[0])
        elif isinstance(entry, DateEntry):
            entry.delete(0, tk.END)
        elif isinstance(entry, tk.Text):
            entry.delete("1.0", tk.END)
        else:
            entry.delete(0, tk.END)


def show_all_projects():
    try:
        for item in tree.get_children():
            tree.delete(item)
        for i, project in enumerate(projects):
            insert_project_to_tree(project, i)
    except Exception as e:
        print(f"显示所有项目时出现异常：{str(e)}")
        traceback.print_exc()
        messagebox.showerror("错误", f"显示所有项目失败：{str(e)}")


def clear_and_insert(entry, value):
    """
    清空输入框并插入新值的辅助函数
    :param entry: 输入框对象
    :param value: 要插入的值
    """
    if isinstance(entry, tk.Text):
        entry.delete("1.0", tk.END)
        entry.insert(tk.END, value)
    elif isinstance(entry, tk.Entry):
        entry.delete(0, tk.END)
        entry.insert(0, value)


def fill_inputs_with_selected(event=None):
    try:
        # 获取当前在表格中被选中的数据项
        selected_item = tree.selection()
        # 检查是否有数据项被选中，如果没有则函数直接返回，不执行后续操作
        if not selected_item:
            return
        # 由于一次只能选中一个数据项，所以取选中项列表的第一个元素
        item = selected_item[0]
        # 获取选中项的具体数据值
        values = tree.item(item, "values")
        # 从第二个字段开始遍历，因为第一个字段通常是序号，不需要填充
        for i, col in enumerate(columns[1:]):
            try:
                if col == "需求来源":
                    # 设置需求来源的选项菜单的值为选中项对应的值
                    selected_source.set(values[i + 1])
                elif col == "定制时间":
                    # 检查对应输入框是否为 DateEntry 类型
                    if isinstance(entries[i], DateEntry):
                        # 如果是 DateEntry 类型，使用 set_date 方法设置日期
                        entries[i].set_date(values[i + 1])
                    else:
                        # 如果不是 DateEntry 类型，调用辅助函数清空并插入新值
                        clear_and_insert(entries[i], values[i + 1])
                else:
                    # 对于其他类型的输入框，调用辅助函数清空并插入新值
                    clear_and_insert(entries[i], values[i + 1])
            except Exception as inner_e:
                # 记录字段填充时的异常信息
                logging.error(f"填充字段 {col} 时出现异常: {str(inner_e)}")
                messagebox.showerror("错误", f"填充字段 {col} 失败: {str(inner_e)}")
    except Exception as e:
        # 记录整个填充过程的异常信息
        logging.error(f"填充输入框时出现异常: {str(e)}")
        traceback.print_exc()
        messagebox.showerror("错误", f"填充输入框失败: {str(e)}")


def export_to_excel():
    try:
        save_projects_to_excel(file_path, projects)
        messagebox.showinfo("提示", "导出成功！")
    except Exception as e:
        print(f"导出 Excel 文件时出现异常：{str(e)}")
        traceback.print_exc()
        messagebox.showerror("错误", f"导出失败：{str(e)}")


def update_project_numbers():
    for i, project in enumerate(projects):
        project["序号"] = i + 1


def update_project_number_options():
    project_numbers = ["全部项目"] + [project["项目编号"] for project in projects]
    selected_project_number_var.set("全部项目")
    option_menu_project_number['menu'].delete(0, 'end')
    for number in project_numbers:
        option_menu_project_number['menu'].add_command(label=number, command=lambda value=number: selected_project_number_var.set(value))


if __name__ == "__main__":
    try:
        print("程序开始运行")

        # 创建主窗口
        root = tk.Tk()
        root.title("项目信息总结")
        root.geometry("1200x800")
        root.configure(bg="#f0f0f0")
        print("主窗口创建成功")

        # 添加标题
        '''
        title_label = tk.Label(root, text="BIOS项目查询助手", font=TITLE_FONT, bg="#f0f0f0")
        title_label.pack(pady=20)
        '''

        # 加载 logo 图片
        '''
        try:
            logo_image = Image.open("logo.png")
            logo_image = logo_image.resize((100, 100), Image.LANCZOS)
            logo_photo = ImageTk.PhotoImage(logo_image)
            logo_label = tk.Label(root, image=logo_photo, bg="#f0f0f0")
            logo_label.image = logo_photo
            logo_label.pack(anchor=tk.NW, padx=10, pady=10)
        except FileNotFoundError:
            print("未找到 logo.png 文件，跳过添加 logo")
        except Exception as e:
            print(f"加载 logo 图片时出现异常：{str(e)}，跳过添加 logo")
        '''

        # 设置样式
        style = ttk.Style()
        style.theme_use("default")
        try:
            style.configure("Treeview", background="#f9f9f9", foreground="black", rowheight=25, fieldbackground="#f9f9f9",
                            font=FONT)
            print("Treeview 样式设置成功")
        except Exception as e:
            print(f"设置 Treeview 字体时出现异常：{str(e)}，使用默认字体")
            style.configure("Treeview", background="#f9f9f9", foreground="black", rowheight=25, fieldbackground="#f9f9f9")

        # 创建输入框和标签
        input_frame = tk.Frame(root, bg="#f0f0f0")
        input_frame.pack(pady=10, padx=20, fill=tk.X)
        print("输入框架创建成功")

        labels = columns[1:]
        entries = []
        selected_source = tk.StringVar(root)
        selected_source.set(source_options[0])  # 默认选择第一个选项

        max_cols = 4
        max_rows = 3

        for i, label_text in enumerate(labels):
            row = i // max_cols
            col = i % max_cols

            label = tk.Label(input_frame, text=label_text, bg="#f0f0f0", font=FONT_BOLD)
            label.grid(row=row * 2, column=col, padx=10, pady=5, sticky="w")

            if label_text == "需求来源":
                option_menu = tk.OptionMenu(input_frame, selected_source, *source_options)
                option_menu.config(font=FONT, bg="white", relief="flat", highlightthickness=0)
                option_menu.grid(row=row * 2 + 1, column=col, padx=10, pady=5, sticky="w")
                entries.append(option_menu)
            elif label_text == "定制时间":
                custom_time_entry = DateEntry(input_frame, font=FONT, width=30, date_pattern='yyyy-mm-dd')
                custom_time_entry.grid(row=row * 2 + 1, column=col, padx=10, pady=5, sticky="w")
                entries.append(custom_time_entry)
            elif label_text in ["git 分支和路径", "备注"]:
                entry = tk.Text(input_frame, font=FONT, width=30, height=5)
                entry.grid(row=row * 2 + 1, column=col, padx=10, pady=5, rowspan=3, columnspan=1)
                entries.append(entry)
            else:
                entry = tk.Entry(input_frame, font=FONT, width=30)
                entry.grid(row=row * 2 + 1, column=col, padx=10, pady=5)
                entries.append(entry)

        # 项目编号选择框和操作按钮
        filter_frame = tk.Frame(root, bg="#f0f0f0")
        filter_frame.pack(pady=10, padx=20, fill=tk.X)
        print("筛选框架创建成功")

        label_project_number = tk.Label(filter_frame, text="选择项目编号:", bg="#f0f0f0", font=FONT_BOLD)
        label_project_number.grid(row=0, column=0, padx=10, pady=5, sticky="w")
        print("项目编号标签创建成功")

        selected_project_number_var = tk.StringVar(root)
        project_numbers = ["全部项目"] + [project["项目编号"] for project in projects]
        selected_project_number_var.set("全部项目")
        option_menu_project_number = tk.OptionMenu(filter_frame, selected_project_number_var, *project_numbers, command=lambda _: filter_project())
        option_menu_project_number.config(font=FONT, bg="white", relief="flat", highlightthickness=0)
        option_menu_project_number.grid(row=0, column=1, padx=10, pady=5)
        print("项目编号选择框创建成功")

        button_add = tk.Button(filter_frame, text="新增项目", command=add_project, font=FONT, bg="#4CAF50", fg="white")
        button_add.grid(row=0, column=2, padx=10, pady=5)
        print("新增项目按钮创建成功")

        button_modify = tk.Button(filter_frame, text="修改项目", command=modify_project, font=FONT, bg="#FFC107", fg="white")
        button_modify.grid(row=0, column=3, padx=10, pady=5)
        print("修改项目按钮创建成功")

        button_delete = tk.Button(filter_frame, text="删除项目", command=delete_project, font=FONT, bg="#F44336", fg="white")
        button_delete.grid(row=0, column=4, padx=10, pady=5)
        print("删除项目按钮创建成功")

        # 新增创建文件按钮
        button_create_file = tk.Button(filter_frame, text="创建 Excel 文件", command=lambda: check_and_create_excel(file_path), font=FONT, bg="#2196F3", fg="white")
        button_create_file.grid(row=0, column=5, padx=10, pady=5)
        print("创建 Excel 文件按钮创建成功")

        # 创建 Treeview 表格
        tree = ttk.Treeview(root, columns=columns, show="headings")
        for col in columns:
            tree.heading(col, text=col)
            tree.column(col, width=100)  # 设置列宽
        tree.pack(pady=10)

        # 绑定表格选择事件
        tree.bind("<<TreeviewSelect>>", fill_inputs_with_selected)

        # 显示所有项目
        show_all_projects()

        # 添加版权声明及免责声明
        disclaimer_text = "版权所有 2025 (C) CETC    法律声明        \n" \
                          "免责声明：由于产品版本升级或其他原因，本工具内容会不定期进行更新。本工具仅作为使用参考，本工具中的所有陈述、信息和建议不构成任何明示或暗示的担保。"
        disclaimer_label = tk.Label(root, text=disclaimer_text, bg="#f0f0f0", font=DISCLAIMER_FONT, justify=tk.CENTER, anchor="center")
        disclaimer_label.pack(pady=10, fill=tk.X)

        # 启动主事件循环
        root.mainloop()

    except Exception as e:
        print(f"程序运行过程中出现异常：{str(e)}")
        traceback.print_exc()
    